package com.sinsz.common;


import com.alipay.sofa.rpc.config.ConsumerConfig;
import com.sinsz.common.bolt.Cache;
import com.sinsz.common.bolt.ProviderBean;
import com.sinsz.common.bolt.ReferenceBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Bolt服务操作工具
 * @author chenjianbo
 */
public class BoltUtils {

    private static BoltUtils ourInstance = new BoltUtils();

    private static final Logger logger = LoggerFactory.getLogger(BoltUtils.class);

    public static BoltUtils getInstance() {
        return ourInstance;
    }

    private BoltUtils() {
    }

    private Cache cache = new Cache<>();

    @SuppressWarnings("unchecked")
    private <T> Cache<T> cache() {
        return cache;
    }

    /**
     * 获取所有配置的暴露服务实例
     * <p>
     *     内部发布使用
     * </p>
     * @param <T>
     * @return
     */
    <T> List<ProviderBean<T>> getProviderBeans() {
        Cache<T> c = cache();
        return c.getProviders().entrySet()
                .stream()
                .map(Map.Entry::getValue)
                .collect(Collectors.toList());
    }

    /**
     * 获取所有配置的消费服务实例
     * @param <T>
     * @return
     */
    <T> List<ReferenceBean<T>> getReferenceBeans() {
        Cache<T> c = cache();
        return c.getReferences().entrySet()
                .stream()
                .map(Map.Entry::getValue)
                .collect(Collectors.toList());
    }

    /**
     * 设置消费配置对象
     * @param clz
     * @param object
     * @param <T>
     */
    <T> void putBean(@NotNull Class<T> clz, @NotNull ConsumerConfig<T> object) {
        Cache<T> c = cache();
        c.getBeans().put(clz.getName(), object);
    }


    /**
     * 新增暴露服务
     * @param clz   暴露类
     * @param ref   暴露类对应的注入对象
     * @param <T>
     */
    public <T> void addProvider(@NotNull Class<T> clz, @NotNull T ref) {
        List<String> names = Arrays.stream(ref.getClass().getInterfaces())
                .map(Class::getName)
                .collect(Collectors.toList());
        names.add(ref.getClass().getName());
        if (!names.contains(clz.getName())) {
            logger.error("发布服务失败! 服务名：" + clz.getName());
            return;
        }
        Cache<T> c = cache();
        c.getProviders().put(clz.getName(), new ProviderBean<>(clz, ref));
    }

    /**
     * 新增消费服务
     * @param clz   消费类
     * @param fb    降级方案的消费实现类
     * @param <T>
     */
    public <T> void addReference(@NotNull Class<T> clz, @NotNull T fb) {
        List<String> names = Arrays.stream(fb.getClass().getInterfaces())
                .map(Class::getName)
                .collect(Collectors.toList());
        if (!names.contains(clz.getName())) {
            logger.error("配置消费实例失败! 实例名：" + clz.getName());
            return;
        }
        Cache<T> c = cache();
        c.getReferences().put(clz.getName(), new ReferenceBean<>(clz, fb));
    }

    /**
     * 业务中调用实例对象
     * @param clz   目标类
     * @param <T>
     * @return
     */
    public <T> Optional<T> getBean(@NotNull Class<T> clz) {
        Cache<T> c = cache();
        ConsumerConfig<T> object = c.getBeans().getOrDefault(clz.getName(), null);
        if (object != null) {
            return Optional.of(object.refer());
        }
        return Optional.empty();
    }

}
